﻿using System;
using System.Collections.Generic;
using System.IO.Packaging;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using WinFormLogger.Logging;

namespace WinFormLogger.Communication
{
    public class TcpClientManager : CommunicationBase
    {
        Logger logger;
        TcpClient? client;

        NetworkStream? stream;

        Task receiveTask;

        /// <summary>
        /// 服务器IP
        /// </summary>
        string ServerIp { get; }

        /// <summary>
        /// 服务器端口
        /// </summary>
        int ServerPort { get; }
        public TcpClientManager(string ip, int port, ProtocolParse protocolParse = null)
        {
            logger = Logger.Instance;
            ServerIp = ip;
            ServerPort = port;
            
        }

        /// <summary>
        /// 连接方法
        /// </summary>
        /// <returns></returns>
        public override async Task<bool> ConnnectAsync()
        {
            try
            {
                if (IsConnected)
                {
                    await DisconnectAsync();
                    await Task.Delay(100);
                }
                client = new TcpClient();

                //连接后判断是否连接超时
                var connectTask = client.ConnectAsync(ServerIp, ServerPort);
                var timoutTask = Task.Delay(ConnectTimeout);
                var completeTask = Task.WhenAny(connectTask, timoutTask);
                if (completeTask == timoutTask)
                {
                    throw new TimeoutException("连接服务器超时");
                }

                stream = client.GetStream();
                //更改连接状态
                OnConnectStatusChanged(true);

                //启动发送线程
                StartSendingTask();

                //启动接收线程
                receiveTask = Task.Run(ReceiveDataAsync);
                return true;
            }
            catch (Exception ex)
            {
                OnErrorOccured(ex);
                await DisconnectAsync();
                return false;
            }
        }

        protected int bufferSize { get; set; } = 4096;
        private async Task ReceiveDataAsync()
        {
            byte[] buffer = new byte[bufferSize];
            try
            {
                while (IsConnected && stream != null && !cancellationTokenSource.IsCancellationRequested)
                {
                    int bytesRead = 0;
                    try
                    {
                        bytesRead = await stream.ReadAsync(buffer,0,buffer.Length);
                    }
                    catch(ObjectDisposedException ex)
                    {
                        logger.Error("资源释放，已取消接收");
                        return;
                    }
                    if (bytesRead <= 0)
                    {
                        await DisconnectAsync();
                        break;
                    }
                    byte[] data = new byte[bytesRead];
                    Array.Copy(buffer,data,bytesRead);

                    if (protocolParse != null)
                    {
                        protocolParse.ParseData(data);
                    }
                    else
                    {
                        var args = new MesseageEventArgs(data, Encoding.UTF8.GetString(data), MessageDirection.Receive);
                        OnMessageReceive(args);
                    }
                }
            }
            catch(TaskCanceledException ex)
            {
                logger.Error("取消接收");
            }
            catch(Exception ex)
            {
                OnErrorOccured(ex);
                await DisconnectAsync();
            }
        }



        /// <summary>
        /// 断开方法
        /// </summary>
        /// <returns></returns>
        public override async Task DisconnectAsync()
        {
            try
            {
                OnConnectStatusChanged(false);
                if (cancellationTokenSource != null && !cancellationTokenSource.IsCancellationRequested)
                {
                    cancellationTokenSource.Cancel();
                    await Task.Delay(50);
                }
                
                if (stream != null)
                {
                    stream.Close();
                    stream = null;
                }
                if (client != null)
                {
                    client.Close();
                    client = null;
                }
                //清空发送队列
                while (SendQueue.TryDequeue(out _)) { }
                //清空协议解析器缓冲区
                protocolParse?.ClearBuffer();

                if (protocolParse != null)
                {
                    protocolParse.MessageReceive -= HandlePacketReceive;
                    protocolParse.MessageReceive += HandlePacketReceive;
                }
                await Task.CompletedTask;//任务完成返回
            }
            catch (Exception ex)
            {
                logger.Error($"{ex.Message}");
            }
        }

        private void HandlePacketReceive(object? sender, byte[] e)
        {
            if (protocolParse == null)
                return;
            var payload = protocolParse.ExtractPayload(e);
            var args = new MesseageEventArgs(e,Encoding.UTF8.GetString(payload),MessageDirection.Receive,payload);
            OnMessageReceive(args);
        }

        protected override async Task ProcessSendQueueAsync()
        {
            try
            {
                var token = cancellationTokenSource.Token;
                while (!token.IsCancellationRequested)
                {
                    //logger.Info("测试处理数据");
                    if (SendQueue.TryDequeue(out byte[] data))
                    {
                        try
                        {
                            await stream.WriteAsync(data, 0, data.Length);

                            //触发消息发送事件
                            var args = new MesseageEventArgs(data, Encoding.UTF8.GetString(data), MessageDirection.Send);
                            OnMessageSend(args);
                        }
                        catch (Exception ex)
                        {
                            logger.Error($"{ex.Message}");
                            await DisconnectAsync();
                            break;
                        }
                    }
                    else
                    {
                        await Task.Delay(10, token);
                    }
                }
            }
            catch(Exception ex)
            {
                OnErrorOccured(ex);
            }
        }

        public override async Task<bool> SendAsync(byte[] data)
        {
            //重连功能

            try
            {
                byte[] sendData = protocolParse != null ? protocolParse.WrapData(data) : data;
                SendQueue.Enqueue(sendData);
                return await Task.FromResult(true);
            }
            catch(Exception ex)
            {
                logger.Error($"{ex.Message}");
                return false;
            }
        }
    }
}
